﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;
using UtfprLibrary.ComponentModel.Security;
using UtfprLibrary.Windows.Forms.ComponentModel;
using UtfprLibrary.Windows.Forms.ComponentModel.Security;
using System.Threading.Tasks;
using UtfprLibrary.Windows.Forms.Exceptions;

namespace UtfprLibrary.Windows.Forms {
    public partial class UtfprFormCrudBase : UtfprFormBase {
        #region Constructor

        public UtfprFormCrudBase() {
            InitializeComponent();
        }

        #endregion

        #region Properties

        private UtfprByKeyBase _utfprByKey;
        /// <summary>
        /// TODO
        /// </summary>
        [Browsable(false)]
        public UtfprByKeyBase UtfprByKey {
            get {
                if (_utfprByKey == null) {
                    FieldInfo field = null;
                    var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var fieldName = UtfprWindowsFormsConsts.UtfprFormCrud_UtfprByKey_FieldName;
                    var frmCrud = this.GetType();

                    field = frmCrud.GetField(fieldName, flags);

                    while (field == null) {
                        if (field == null) {
                            //limita a verificação na hierarquia até no máximo Form
                            if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                                //recebe o tipo base
                                frmCrud = frmCrud.BaseType;
                            } else {
                                break;
                            }
                        }

                        field = frmCrud.GetField(fieldName, flags);
                    }

                    if (field != null) {
                        _utfprByKey = field.GetValue(this) as UtfprByKeyBase;
                    }
                }
                return _utfprByKey;
            }
        }

        private StatusStrip _statusStrip;
        /// <summary>
        /// TODO
        /// </summary>
        [Browsable(false)]
        public StatusStrip StatusStrip {
            get {
                if (_statusStrip == null) {
                    FieldInfo field = null;
                    var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var fieldName = UtfprWindowsFormsConsts.UtfprFormCrud_StatusStrip_FieldName;
                    var frmCrud = this.GetType();

                    field = frmCrud.GetField(fieldName, flags);

                    while (field == null) {
                        //limita a verificação na hierarquia até no máximo Form
                        if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                            //recebe o tipo base
                            frmCrud = frmCrud.BaseType;
                        } else {
                            break;
                        }

                        field = frmCrud.GetField(fieldName, flags);
                    }

                    if (field != null) {
                        _statusStrip = field.GetValue(this) as StatusStrip;
                    }
                }

                return _statusStrip;
            }
        }

        private UtfprBindingNavigatorBase _ubnMaster;
        /// <summary>
        /// TODO
        /// do not remove this property (utfprformpickereditor needs it)
        /// 
        /// UtfprLibraryConstants 
        /// -> public const string UtfprBindingNavigator_Master_PropertyName = "UBNMaster";
        /// </summary>
        [Browsable(false)]
        private UtfprBindingNavigatorBase UBNMaster {
            get {
                if (_ubnMaster == null) {
                    List<FieldInfo> allFields = new List<FieldInfo>();

                    //herança
                    allFields.AddRange(
                        this.GetType().GetFields(
                            BindingFlags.NonPublic | BindingFlags.Instance)
                    );

                    //composição
                    allFields.AddRange(
                        this.GetType().BaseType.GetFields(
                            BindingFlags.NonPublic | BindingFlags.Instance)
                    );

                    try {
                        _ubnMaster = (from info in allFields
                                      where typeof(UtfprBindingNavigatorBase).IsAssignableFrom(info.FieldType)
                                      select info.GetValue(this) as UtfprBindingNavigatorBase)
                                        .Where(navigator => navigator.CurrentMode == UBNModeEnum.Master)
                                        .FirstOrDefault();
                    } catch (Exception ex) {
                        throw new UtfprWFCoreFormsException("", ex);
                    }
                }
                return _ubnMaster;
            }
        }

        private List<UtfprLookupFieldBase> _lkpFields;
        /// <summary>
        /// TODO
        /// do not remove this property (utfprformpickereditor needs it)
        /// 
        /// UtfprLibraryConstants 
        /// -> public const string UtfprBindingNavigator_Master_PropertyName = "UBNMaster";
        /// </summary>
        [Browsable(false)]
        private List<UtfprLookupFieldBase> LkpFields {
            get {
                if (_lkpFields == null) {
                    List<FieldInfo> allFields = new List<FieldInfo>();

                    //herança
                    allFields.AddRange(
                        this.GetType().GetFields(
                            BindingFlags.NonPublic | BindingFlags.Instance)
                    );

                    //composição
                    allFields.AddRange(
                        this.GetType().BaseType.GetFields(
                            BindingFlags.NonPublic | BindingFlags.Instance)
                    );

                    try {
                        _lkpFields = (from info in allFields
                                      where typeof(UtfprLookupFieldBase).IsAssignableFrom(info.FieldType)
                                      select info.GetValue(this) as UtfprLookupFieldBase).ToList();
                    } catch (Exception ex) {
                        throw new UtfprWFCoreFormsException("", ex);
                    }

                }
                return _lkpFields;
            }
        }

        private bool _isEnterTab = false;
        /// <summary>
        /// Sets whether the "Enter" key behaves like the "Tab" key 
        /// </summary>
        [Category("Behavior")]
        [Description("Sets whether the Enter key behaves like the Tab key")]
        public bool IsEnterTab {
            get { return _isEnterTab; }
            set { _isEnterTab = value; }
        }

        #endregion

        #region EventHandlers

        private void UtfprCrudBase_Load(object sender, EventArgs e) {
            if (!UtfprControlBase.IsInDesignMode) {
                if (UtfprByKey != null) {
                    UtfprByKey.ButtonGo.Click += new EventHandler(ButtonGo_Click);
                    UtfprByKey.TextBoxId.KeyPress += new KeyPressEventHandler(TextBoxId_KeyPress);
                }
            }
            KeyPress += new KeyPressEventHandler(UtfprCrudBase_KeyPress);
            FormClosing += new FormClosingEventHandler(UtfprFormCrudBase_FormClosing);
            applyUserPermissions();
        }

        void UtfprFormCrudBase_FormClosing(object sender, FormClosingEventArgs e) {
            if (UBNMaster.CurrentState == UBNStateEnum.Adding || UBNMaster.CurrentState == UBNStateEnum.Updating) {
                MessageBox.Show(UtfprWindowsFormsConsts.UtfprFormCrudBase_FormClosing_MessageBoxText, UtfprWindowsFormsConsts.UtfprFormCrudBase_FormClosing_MessageBoxCaption, MessageBoxButtons.OK);
                // Cancel the Closing event
                e.Cancel = true;
            }
        }

        private void UtfprCrudBase_KeyPress(object sender, KeyPressEventArgs e) {
            if (IsEnterTab && e.KeyChar == (char)Keys.Enter) {
                SendKeys.Send("{TAB}");
            }
        }

        private void TextBoxId_KeyPress(object sender, KeyPressEventArgs e) {
            //chama a busca por id quando pressiona o enter
            if (e.KeyChar == (char)Keys.Enter) {
                e.Handled = false;
                string txtId = ((TextBox)sender).Text;
                if (txtId == string.Empty) {
                    UpdateStatusStrip("Id não encontrado.");
                } else {
                    if (UtfprByKey.IsString) {
                        QueryById(txtId);
                    } else {
                        int intId;
                        if (!(int.TryParse(txtId, out intId))) {
                            UpdateStatusStrip("Erro de conversão.");
                        } else {
                            QueryById(intId);
                        }
                    }
                    UtfprByKey.TextBoxId.Text = string.Empty;
                }
                return;
            }
        }

        private void ButtonGo_Click(object sender, EventArgs e) {
            string txtId = UtfprByKey.TextBoxId.Text;

            if (txtId == string.Empty) {
                UpdateStatusStrip("Id não encontrado.");
            } else {
                if (UtfprByKey.IsString) {
                    QueryById(txtId);
                } else {
                    int intId;
                    if (!(int.TryParse(txtId, out intId))) {
                        UpdateStatusStrip("Erro de conversão.");
                    } else {
                        QueryById(intId);
                    }
                }
                UtfprByKey.TextBoxId.Text = string.Empty;
            }
        }

        #endregion

        #region PublicMethods

        public void UpdateStatusStrip(string status) {
            if (StatusStrip != null) {
                if (StatusStrip.Items.ContainsKey(UtfprWindowsFormsConsts.UtfprFormCrud_StatusStripLabel_FieldName)) {
                    StatusStrip.Items[UtfprWindowsFormsConsts.UtfprFormCrud_StatusStripLabel_FieldName].Text = status;
                }
            }
        }

        public virtual UtfprFormQueryBase GetUtfprQuery() {
            return null;
        }

        #endregion

        #region InternalMethods

        internal void QueryById(object id) {
            UBNMaster.QueryById(id);

            //foreach (var lkp in LkpFields) {
            //    lkp.Fetch();
            //}
        }

        #endregion

        #region Security

        private bool isOperationPermited(int operationKey) {
            foreach (var restriction in UtfprSecurity.Instance.User.Restrictions.ToList()) {
                foreach (var function in restriction.FunctionsAndOperations.Keys.ToList()) {
                    foreach (var operation in restriction.FunctionsAndOperations[function].ToList()) {
                        if (operationKey == operation.Key) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        private bool isFunctionPermited(int functionKey) {
            foreach (var restriction in UtfprSecurity.Instance.User.Restrictions.ToList()) {
                foreach (var function in restriction.FunctionsAndOperations.Keys.ToList()) {
                    if (functionKey == function.Key) {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Based os user permissions, Enable/Disable all controls marked with property IsSecure=True
        /// </summary>
        private void applyUserPermissions() {
            if (UtfprSecurity.Instance.IsUserConected) {
                #region button

                foreach (var navigator in this.Controls.OfType<TableLayoutPanel>().First().Controls.OfType<UtfprBindingNavigatorBase>().ToList()) {
                    foreach (var item in navigator.Items.OfType<IUtfprRestrictionService>().ToList()) {
                        if (item.IsSecureRestriction) {
                            bool isVisible = false;
                            if (item.FunctionOrOperationRestriction != null) {
                                if (item.IsFunctionRestriction) {
                                    isVisible = isFunctionPermited((item.FunctionOrOperationRestriction as IUtfprKeyName).Key);
                                } else {
                                    isVisible = isOperationPermited((item.FunctionOrOperationRestriction as IUtfprKeyName).Key);
                                }
                            }
                            item.SetVisibleRestriction(isVisible);
                        }
                    }
                }

                #endregion
            }
        }

        #endregion
    }
}